#pragma once

#include <asm/page.h>
#include <linux/stdlib.h>

struct kmem_cache;

#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1)

typedef struct kmem_cache *kmem_buckets[KMALLOC_SHIFT_HIGH + 1];

#define RANDOM_KMALLOC_CACHES_NR 0

/*
 * Whenever changing this, take care of that kmalloc_type() and
 * create_kmalloc_caches() still work as intended.
 *
 * KMALLOC_NORMAL can contain only unaccounted objects whereas KMALLOC_CGROUP
 * is for accounted but unreclaimable and non-dma objects. All the other
 * kmem caches can have both accounted and unaccounted objects.
 */
enum kmalloc_cache_type
{
    KMALLOC_NORMAL = 0,
#ifndef CONFIG_ZONE_DMA
    KMALLOC_DMA = KMALLOC_NORMAL,
#endif
#ifndef CONFIG_MEMCG
    KMALLOC_CGROUP = KMALLOC_NORMAL,
#endif
    KMALLOC_RANDOM_START = KMALLOC_NORMAL,
    KMALLOC_RANDOM_END = KMALLOC_RANDOM_START + RANDOM_KMALLOC_CACHES_NR,
#ifdef CONFIG_SLUB_TINY
    KMALLOC_RECLAIM = KMALLOC_NORMAL,
#else
    KMALLOC_RECLAIM,
#endif
#ifdef CONFIG_ZONE_DMA
    KMALLOC_DMA,
#endif
#ifdef CONFIG_MEMCG
    KMALLOC_CGROUP,
#endif
    NR_KMALLOC_TYPES
};

typedef unsigned long slab_flags_t;

struct kmem_cache_args
{
    /**
     * @align: The required alignment for the objects.
     *
     * %0 means no specific alignment is requested.
     */
    unsigned int align;
    /**
     * @useroffset: Usercopy region offset.
     *
     * %0 is a valid offset, when @usersize is non-%0
     */
    unsigned int useroffset;
    /**
     * @usersize: Usercopy region size.
     *
     * %0 means no usercopy region is specified.
     */
    unsigned int usersize;
    /**
     * @freeptr_offset: Custom offset for the free pointer
     * in &SLAB_TYPESAFE_BY_RCU caches
     *
     * By default &SLAB_TYPESAFE_BY_RCU caches place the free pointer
     * outside of the object. This might cause the object to grow in size.
     * Cache creators that have a reason to avoid this can specify a custom
     * free pointer offset in their struct where the free pointer will be
     * placed.
     *
     * Note that placing the free pointer inside the object requires the
     * caller to ensure that no fields are invalidated that are required to
     * guard against object recycling (See &SLAB_TYPESAFE_BY_RCU for
     * details).
     *
     * Using %0 as a value for @freeptr_offset is valid. If @freeptr_offset
     * is specified, %use_freeptr_offset must be set %true.
     *
     * Note that @ctor currently isn't supported with custom free pointers
     * as a @ctor requires an external free pointer.
     */
    unsigned int freeptr_offset;
    /**
     * @use_freeptr_offset: Whether a @freeptr_offset is used.
     */
    bool use_freeptr_offset;
    /**
     * @ctor: A constructor for the objects.
     *
     * The constructor is invoked for each object in a newly allocated slab
     * page. It is the cache user's responsibility to free object in the
     * same state as after calling the constructor, or deal appropriately
     * with any differences between a freshly constructed and a reallocated
     * object.
     *
     * %NULL means no constructor.
     */
    void (*ctor)(void *);
};

#define SLAB_NO_OBJ_EXT 0
#define SLAB_HWCACHE_ALIGN	0//__SLAB_FLAG_BIT(_SLAB_HWCACHE_ALIGN)
/* Indicate a kmalloc slab */
#define SLAB_KMALLOC 0 // todo	__SLAB_FLAG_BIT(_SLAB_KMALLOC)

void *__kmalloc_noprof(size_t size, gfp_t flags);
void *kmem_cache_alloc_noprof(struct kmem_cache *s, gfp_t gfpflags);

#define kmem_cache_zalloc(_k, _flags) kmem_cache_alloc_noprof(_k, (_flags)|__GFP_ZERO)
